Micron Document
🎖️GitЯра🎖️


Displaying Raw • Download

feature/firmware/src/commonMain/kotlin/org/meshtastic/feature/firmware/ota/BleScanSupport.kt 2d20cd8a4708e2ef66e98d5259f3a97ec93f240a (2d20cd8a) Text, 5.39 KB

T8b949e/*
* Copyright (c) 2026 Meshtastic LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
Tff7b72package T7ee787org.meshtastic.feature.firmware.ota

Tff7b72import T7ee787co.touchlab.kermit.Logger
Tff7b72import T7ee787kotlinx.coroutines.TimeoutCancellationException
Tff7b72import T7ee787kotlinx.coroutines.channels.Channel
Tff7b72import T7ee787kotlinx.coroutines.coroutineScope
Tff7b72import T7ee787kotlinx.coroutines.currentCoroutineContext
Tff7b72import T7ee787kotlinx.coroutines.delay
Tff7b72import T7ee787kotlinx.coroutines.ensureActive
Tff7b72import T7ee787kotlinx.coroutines.flow.first
Tff7b72import T7ee787kotlinx.coroutines.flow.firstOrNull
Tff7b72import T7ee787kotlinx.coroutines.flow.onEach
Tff7b72import T7ee787kotlinx.coroutines.launch
Tff7b72import T7ee787kotlinx.coroutines.withTimeout
Tff7b72import T7ee787org.meshtastic.core.ble.BleConnection
Tff7b72import T7ee787org.meshtastic.core.ble.BleConnectionState
Tff7b72import T7ee787org.meshtastic.core.ble.BleDevice
Tff7b72import T7ee787org.meshtastic.core.ble.BleScanner
Tff7b72import T7ee787kotlin.time.Duration
Tff7b72import T7ee787kotlin.time.Duration.Companion.seconds

Tff7b72internal Tff7b72const Tff7b72val Te6edf3DEFAULT_SCAN_RETRY_COUNT Tff7b72= T79c0ff3
Tff7b72internal Tff7b72val Te6edf3DEFAULT_SCAN_RETRY_DELAYTb4b4b4: Te6edf3Duration Tff7b72= T79c0ff2.Te6edf3seconds
Tff7b72internal Tff7b72val Te6edf3DEFAULT_SCAN_TIMEOUTTb4b4b4: Te6edf3Duration Tff7b72= T79c0ff1T79c0ff0.Te6edf3seconds

Tff7b72private Tff7b72const Tff7b72val Te6edf3MAC_PARTS_COUNT Tff7b72= T79c0ff6
Tff7b72private Tff7b72const Tff7b72val Te6edf3HEX_RADIX Tff7b72= T79c0ff1T79c0ff6
Tff7b72private Tff7b72const Tff7b72val Te6edf3BYTE_MASK Tff7b72= T79c0ff0Te6edf3xFF

T8b949e/**
* Increment the last byte of a BLE MAC address by one.
*
* Both ESP32 (OTA) and nRF52 (DFU) devices advertise with the original MAC + 1 after rebooting into their respective
* firmware-update modes.
*/
Tf0883e@SuppressTb4b4b4(Ta5d6ff"Ta5d6ffReturnCountTa5d6ff"Tb4b4b4)
Tff7b72internal Tff7b72fun Td2a8ffcalculateMacPlusOneTb4b4b4(Te6edf3macAddressTb4b4b4: Tffa657StringTb4b4b4)Tb4b4b4: Tffa657String Tb4b4b4{
Tff7b72val Te6edf3parts Tff7b72= Te6edf3macAddressTb4b4b4.Te6edf3splitTb4b4b4(Ta5d6ff"Ta5d6ff:Ta5d6ff"Tb4b4b4)
Tff7b72if Tb4b4b4(Te6edf3partsTb4b4b4.Te6edf3size Tff7b72!Tff7b72= Te6edf3MAC_PARTS_COUNTTb4b4b4) Tff7b72return Te6edf3macAddress
Tff7b72val Te6edf3lastByte Tff7b72= Te6edf3partsTff7b72[Te6edf3MAC_PARTS_COUNT Tff7b72- T79c0ff1Tff7b72]Tb4b4b4.Te6edf3toIntOrNullTb4b4b4(Te6edf3HEX_RADIXTb4b4b4) Tff7b72?: Tff7b72return Te6edf3macAddress
Tff7b72val Te6edf3incremented Tff7b72= Tb4b4b4(Tb4b4b4(Te6edf3lastByte Tff7b72+ T79c0ff1Tb4b4b4) Te6edf3and Te6edf3BYTE_MASKTb4b4b4)Tb4b4b4.Te6edf3toStringTb4b4b4(Te6edf3HEX_RADIXTb4b4b4)Tb4b4b4.Te6edf3uppercaseTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3padStartTb4b4b4(T79c0ff2Tb4b4b4, Ta5d6ff'0'Tb4b4b4)
Tff7b72return Ta5d6ff"Tffd700${Te6edf3partsTb4b4b4.Te6edf3takeTb4b4b4(Te6edf3MAC_PARTS_COUNT Tff7b72- T79c0ff1Tb4b4b4)Tb4b4b4.Te6edf3joinToStringTb4b4b4(Ta5d6ff"Tb4b4b4:Ta5d6ff"Tb4b4b4)Tffd700}Ta5d6ff:Tffd700$Te6edf3incrementedTa5d6ff"
Tb4b4b4}

T8b949e/**
* Scan for a BLE device matching [predicate] with retry logic.
*
* Shared by both [BleOtaTransport] and
* [SecureDfuTransport][org.meshtastic.feature.firmware.ota.dfu.SecureDfuTransport].
*/
Tff7b72internal Tff7b72suspend Tff7b72fun Td2a8ffscanForBleDeviceTb4b4b4(
Te6edf3scannerTb4b4b4: Te6edf3BleScannerTb4b4b4,
Te6edf3tagTb4b4b4: Tffa657StringTb4b4b4,
Te6edf3serviceUuidTb4b4b4: Te6edf3kotlinTb4b4b4.Te6edf3uuidTb4b4b4.Te6edf3UuidTb4b4b4,
Te6edf3retryCountTb4b4b4: Tffa657Int Tff7b72= Te6edf3DEFAULT_SCAN_RETRY_COUNTTb4b4b4,
Te6edf3retryDelayTb4b4b4: Te6edf3Duration Tff7b72= Te6edf3DEFAULT_SCAN_RETRY_DELAYTb4b4b4,
Te6edf3scanTimeoutTb4b4b4: Te6edf3Duration Tff7b72= Te6edf3DEFAULT_SCAN_TIMEOUTTb4b4b4,
Te6edf3predicateTb4b4b4: Tb4b4b4(Te6edf3BleDeviceTb4b4b4) Tff7b72-Tff7b72> Tffa657BooleanTb4b4b4,
Tb4b4b4)Tb4b4b4: Te6edf3BleDevice? Tb4b4b4{
Te6edf3repeatTb4b4b4(Te6edf3retryCountTb4b4b4) Tb4b4b4{ Te6edf3attempt Tff7b72-Tff7b72>
Te6edf3LoggerTb4b4b4.Te6edf3d Tb4b4b4{ Ta5d6ff"Tffd700$Te6edf3tagTa5d6ff: Scan attempt Tffd700${Te6edf3attempt Tff7b72+ T79c0ff1Tffd700}Ta5d6ff/Tffd700$Te6edf3retryCountTa5d6ff" Tb4b4b4}
Tff7b72val Te6edf3foundDevices Tff7b72= Te6edf3mutableSetOfTff7b72<Tffa657StringTff7b72>Tb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3device Tff7b72=
Te6edf3scanner
Tb4b4b4.Te6edf3scanTb4b4b4(Te6edf3timeout Tff7b72= Te6edf3scanTimeoutTb4b4b4, Te6edf3serviceUuid Tff7b72= Te6edf3serviceUuidTb4b4b4)
Tb4b4b4.Te6edf3onEach Tb4b4b4{ Te6edf3d Tff7b72-Tff7b72>
Tff7b72if Tb4b4b4(Te6edf3foundDevicesTb4b4b4.Te6edf3addTb4b4b4(Te6edf3dTb4b4b4.Te6edf3addressTb4b4b4)Tb4b4b4) Tb4b4b4{
Te6edf3LoggerTb4b4b4.Te6edf3d Tb4b4b4{ Ta5d6ff"Tffd700$Te6edf3tagTa5d6ff: Scan found candidate device (name=Tffd700${Te6edf3dTb4b4b4.Te6edf3nameTffd700}Ta5d6ff)Ta5d6ff" Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Tb4b4b4.Te6edf3firstOrNullTb4b4b4(Te6edf3predicateTb4b4b4)
Tff7b72if Tb4b4b4(Te6edf3device Tff7b72!Tff7b72= Tff7b72nullTb4b4b4) Tb4b4b4{
Te6edf3LoggerTb4b4b4.Te6edf3i Tb4b4b4{ Ta5d6ff"Tffd700$Te6edf3tagTa5d6ff: Found target deviceTa5d6ff" Tb4b4b4}
Tff7b72return Te6edf3device
Tb4b4b4}
Te6edf3LoggerTb4b4b4.Te6edf3w Tb4b4b4{ Ta5d6ff"Tffd700$Te6edf3tagTa5d6ff: Target not in Tffd700${Te6edf3foundDevicesTb4b4b4.Te6edf3sizeTffd700}Ta5d6ff devices foundTa5d6ff" Tb4b4b4}
Tff7b72if Tb4b4b4(Te6edf3attempt Tff7b72< Te6edf3retryCount Tff7b72- T79c0ff1Tb4b4b4) Te6edf3delayTb4b4b4(Te6edf3retryDelayTb4b4b4)
Tb4b4b4}
Tff7b72return Tff7b72null
Tb4b4b4}

T8b949e/**
* Receives a single element from this channel within [timeout], translating a [withTimeout] timeout into the
* transport-specific exception supplied by [onTimeout] (e.g. `OtaProtocolException.Timeout` vs `DfuException.Timeout`).
*
* Shared by the response-wait paths of [BleOtaTransport] and
* [SecureDfuTransport][org.meshtastic.feature.firmware.ota.dfu.SecureDfuTransport]. The Legacy DFU transport keeps its
* own drain-and-filter loops (a single timeout bounds the whole drain), so it deliberately does not use this helper.
*/
Tff7b72internal Tff7b72suspend Tff7b72fun Tff7b72<Te6edf3TTff7b72> Td2a8ffChannelTff7b72<Te6edf3TTff7b72>Tb4b4b4.Te6edf3receiveWithinTb4b4b4(Te6edf3timeoutTb4b4b4: Te6edf3DurationTb4b4b4, Te6edf3onTimeoutTb4b4b4: Tb4b4b4(Tb4b4b4) Tff7b72-Tff7b72> Te6edf3ThrowableTb4b4b4)Tb4b4b4: Te6edf3T Tff7b72= Tff7b72try Tb4b4b4{
Te6edf3withTimeoutTb4b4b4(Te6edf3timeoutTb4b4b4) Tb4b4b4{ Te6edf3receiveTb4b4b4(Tb4b4b4) Tb4b4b4}
Tb4b4b4} Tff7b72catch Tb4b4b4(Tf0883e@SuppressTb4b4b4(Ta5d6ff"Ta5d6ffSwallowedExceptionTa5d6ff"Tb4b4b4) Te6edf3eTb4b4b4: Te6edf3TimeoutCancellationExceptionTb4b4b4) Tb4b4b4{
Te6edf3currentCoroutineContextTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3ensureActiveTb4b4b4(Tb4b4b4)
Tff7b72throw Te6edf3onTimeoutTb4b4b4(Tb4b4b4)
Tb4b4b4}

T8b949e/**
* Runs [block] while a watcher waits for the BLE link to drop. If [connectionState][BleConnection.connectionState]
* reaches [Disconnected][BleConnectionState.Disconnected] mid-[block], the watcher throws the result of [onDrop],
* cancelling [block] and surfacing the drop immediately instead of blocking on a write that will never complete.
*
* Shared by the firmware-streaming paths of the Secure and Legacy DFU transports.
*/
Tff7b72internal Tff7b72suspend Tff7b72fun Tff7b72<Te6edf3TTff7b72> Te6edf3BleConnectionTb4b4b4.Td2a8ffwithDisconnectTripwireTb4b4b4(
Te6edf3onDropTb4b4b4: Tb4b4b4(Te6edf3BleConnectionStateTb4b4b4) Tff7b72-Tff7b72> Te6edf3ThrowableTb4b4b4,
Te6edf3blockTb4b4b4: Te6edf3suspend Tb4b4b4(Tb4b4b4) Tff7b72-Tff7b72> Te6edf3TTb4b4b4,
Tb4b4b4)Tb4b4b4: Te6edf3T Tff7b72= Te6edf3coroutineScope Tb4b4b4{
Tff7b72val Te6edf3watcher Tff7b72= Te6edf3launch Tb4b4b4{
Tff7b72val Te6edf3state Tff7b72= Te6edf3connectionStateTb4b4b4.Te6edf3first Tb4b4b4{ Tffa657it Tff7b72is Te6edf3BleConnectionStateTb4b4b4.Te6edf3Disconnected Tb4b4b4}
Tff7b72throw Te6edf3onDropTb4b4b4(Te6edf3stateTb4b4b4)
Tb4b4b4}
Tff7b72try Tb4b4b4{
Te6edf3blockTb4b4b4(Tb4b4b4)
Tb4b4b4} Tff7b72finally Tb4b4b4{
Te6edf3watcherTb4b4b4.Te6edf3cancelTb4b4b4(Tb4b4b4)
Tb4b4b4}
Tb4b4b4}

Served by rngit 1.5.0 - Generated in 0.07s